S3 Event Notificationを別アカウントのリージョンの異なるAmazon SNSに送信し、Lambdaを発火させる
クロスアカウントな構成でS3にファイルが置かれたことを検知し、Lambdaで処理を行いたいといった場合、 同一Regionであれば、S3 Event Notificationを異なるアカウントのAWS Lambdaに対して送信ることで対応が可能です。
ですが、この2つの環境のRegionが異なった場合は、SNSを挟ませる必要があります。
この時作る構成としては以下のようになるかと思います。
以降の説明では、アカウントAを顧客アカウント、アカウントBをサービサーアカウントとして説明します。
上記の記事でこの構成を取りたい例として以下の例が挙げられていました。
これができると何が嬉しいでしょうか。 たとえば、あなたがログ収集プロダクトのSaaSをAWS上で展開するサービサーだとします。 顧客のAWSアカウントでS3にログファイルが出力されたことをトリガーに、 サービサー自身のアカウントでAWS Lambdaを起動して、顧客のログにアクセスし、 ログを取得、加工、再保存することができます。
ですがこの場合、顧客アカウント側の思いとしてはS3に書き出したログを収集してもらいたいのが思いであり、 SNSまで触らなければいけないのは少し負荷のある作業になります。 そのため、この構成を以下のようにしてみたいと思います。
手順
1. S3 バケットの作成(顧客アカウント)
顧客アカウント側にS3バケットを作成します。クロスリージョンを試すため、ここではバージニアで作成をしています。
ここで作成されたBucketのARNは以下となります。
arn:aws:s3:::cm-kajiwara-s3-event-test-us-east-1
2. SNSの作成(サービサーアカウント)
ここで作るSNSはサービサー側に作成します。 この時注意点として、SNSは同一Regionに作る必要があります。 バケットをバージニアで作ったため、こちらもバージニアで作る必要があります。
3.SNSのアクセスポリシーの作成(サービサーアカウント)
ここで顧客アカウント側のS3 バケットからの通知を受けれる設定をする必要があります。
2.で作成したSNSに対して以下のようなアクセスポリシーを追加します。
アクセスポリシーはJSONで書く必要があり、以下のオブジェクトは配列に追加するる形になりますので、
,
の追加も必要です。
{ "Sid": "sns-publish-s3", "Effect": "Allow", "Principal": { "AWS": "*" }, "Action": "SNS:Publish", "Resource": "arn:aws:sns:us-east-1:824966751986:cm-kajiwara-sns-x-account-us-east-1", "Condition": { "ArnLike": { "aws:SourceArn": "arn:aws:s3:::cm-kajiwara-s3-event-test-us-east-1" } } }
4. Lambdaを実装し、作ったSNS TopicにSubscribeするように設定します(サービサーアカウント)
SNS + Lambdaな構成を作ります。様々な方法があるかとは思いますが、一例として以下を紹介します。
今回コードとして、どこのファイルからのイベントなのかは検知したいので以下のようなコードを記載しました。
import json def lambda_handler(event, context): # TODO implement event = json.loads(event['Records'][0]['Sns']['Message']) print(json.dumps(event,indent=4)) return { 'statusCode': 200, 'body': json.dumps('Hello from Lambda!') }
5. S3のイベント通知をサービサーアカウントのSNSに飛ばす設定を行います。(顧客アカウント)
6. S3にファイルを配置し、S3のイベント通知を通知させます。(顧客アカウント)
7. サービサーアカウントのSNSの通知経由でLambdaが発火したことを確認します。(サービサーアカウント)
最後に
クロスアカウント構成において、S3バケットを持ってるアカウント側はS3の設定のみで、別リージョン・別アカウントに対して通知を出すことが可能です。 クロスリージョン・クロスアカウントな構成を作る際に参考になれば幸いです。